home *** CD-ROM | disk | FTP | other *** search
/ BBS in a Box 3 / BBS in a box - Trilogy III.iso / Files / Prog / N-P / NIFTY / myCShell / off_screen.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-12-17  |  9.4 KB  |  322 lines  |  [TEXT/KAHL]

  1. /***************************************************************************
  2.  Apple Macintosh Developer Technical Support
  3.  
  4.  Some of "Skippy White's Famous High Level Off-Screen Map Routines"
  5.  
  6.  "off_screen.c"
  7.  
  8.  These routines provide a high-level interface to the QuickDraw & Color
  9.  Manager routines which allow the creation and manipulation of off-screen
  10.  bitmaps and pixmaps. They are designed to run on any machine with 128K or
  11.  later ROMs.
  12.  
  13.  NOTE that I've modified some of Skippy's routines and that, therefore, any
  14.       resultant errors in syntax or logic belong solely to me.
  15. ****************************************************************************/
  16.  
  17.  
  18. #include "protos"
  19.  
  20. #include "globals.h"
  21. #include "extern.h"
  22.  
  23.  
  24. // Local Prototype:
  25. OffScreenRecHdl    ErrorOut (OSErr error, OffScreenRecHdl COSHdl);
  26.  
  27.  
  28. OffScreenRecHdl    ErrorOut (OSErr error, OffScreenRecHdl COSHdl)    {
  29.  
  30.     (*COSHdl)->CreateOffScreenError = error;
  31.     
  32.     if (error == NewCOSHdlError)    return (nil);
  33.     else                            return (COSHdl);
  34.  
  35. }    /* ErrorOut */
  36.  
  37.  
  38.  
  39. /* ********** */
  40. GDHandle    GetMaxAreaDevice(Rect *globalRect)    {
  41. /* Find the greatest overlap device for the given global rectangle. */
  42.  
  43.         long        area, maxArea;
  44.         GDHandle    result, device;
  45.         Rect        intersection;
  46.  
  47.  
  48.     result = nil;
  49.     ;
  50.     maxArea = 0;
  51.     ;
  52.     device = GetDeviceList();
  53.  
  54.     while (device != nil)    {
  55.         if (TestDeviceAttribute(device, screenDevice))    {
  56.             if (TestDeviceAttribute(device, screenActive))    {
  57.  
  58.                 if (SectRect(globalRect, &((**device).gdRect), &intersection))    {
  59.  
  60.                     area = (long)(intersection.right - intersection.left) * 
  61.                            (long)(intersection.bottom - intersection.top);
  62.  
  63.                     if (area > maxArea)    {
  64.                         result = device;
  65.                         maxArea = area;
  66.                     }    /* if area > maxArea */
  67.  
  68.                 }    /* if SectRect ... */
  69.  
  70.             device = GetNextDevice(device);
  71.             }    /* screenActive */
  72.         }    /* screenDevice */
  73.     }    /* while */
  74.  
  75.     return (result);
  76.  
  77. }    /* GetMaxAreaDevice */
  78.  
  79.  
  80.  
  81. /**************************
  82.  Just plain nifty stuff ...
  83.  **************************/
  84.  
  85.  
  86. OffScreenRecHdl    CreateOffScreen (Rect *myRect)    {
  87. /* Reference: Tech Note #120
  88.    with special thanks to:
  89.                         Jon Zap and
  90.                         Forrest Tanaka of MacDTS
  91.  
  92.    NOTE: Local window coordinates are input, but local
  93.    device coordinates are returned for drawing purposes. */
  94.  
  95.         long            offRowBytes, sizeOfOff, tempSeed;
  96.         Rect            localRect, globRect;
  97.         short            maxDepth;
  98.         register short    i;
  99.         OSErr            err;
  100.         OffScreenRecHdl    COSHdl;
  101.  
  102.  
  103.     COSHdl = (OffScreenRecHdl)NewClearHandle(sizeof(OffScreenRec));
  104.  
  105.     if ((err = MemError()) != noErr)    return ( ErrorOut(NewCOSHdlError, COSHdl) );
  106.  
  107.     MoveHHi(COSHdl);
  108.     HLock(COSHdl);                        /* Lock this sucker down !! */
  109.  
  110.  /* CreateOffScreenError = noErr;   --   We hope !! */
  111.     GetPort(&( (*COSHdl)->origPort ));    /* Used by ToOnScreen. */
  112.     (*COSHdl)->drawingRect = *myRect;    /* Saved for use after call to ToOnScreen. */
  113.  
  114.     globRect = *myRect;                    /* We're about to switch the */
  115.     LocalGlobal(&globRect);                /*   Port to off-screen:     */
  116.  
  117.     if (!gMac2)
  118.     {
  119.         (*COSHdl)->offGrafPtr = &( (*COSHdl)->offGrafPort );
  120.         OpenPort((*COSHdl)->offGrafPtr);
  121.         maxDepth = 1;
  122.     }   /* ... a low-life machine */
  123.     else
  124.     {
  125.  
  126.      /* Figure out how much space we need for our pixel image.  We call
  127.         mommy ROM's GetMaxDevice to get the pixel map from that.
  128.         We do this to cover the case where the pixel image that we wish to
  129.         CopyBits to spans multiple devices (of possibly different depths). */
  130.  
  131.         (*COSHdl)->myMaxDevice = GetMaxDevice(&globRect);
  132.         if ((*COSHdl)->myMaxDevice == nil)    return ( ErrorOut(MaxDevError, COSHdl) );
  133.  
  134.      /* We need to set theGDevice to the device with the maximum pixel
  135.         depth (the one we just found), so the pixel map of the new
  136.         CGrafPort will be copied from one of the proper depth.  Save
  137.         the current GDevice for retrieval later and, then, open the
  138.         new CGrafPort to use for our off-screen drawing.              */
  139.  
  140.         (*COSHdl)->oldDevice = GetGDevice();
  141.         SetGDevice((*COSHdl)->myMaxDevice);
  142.  
  143.         /* Initialize this guy: */
  144.         (*COSHdl)->offCGrafPtr = &( (*COSHdl)->offCGrafPort );
  145.         OpenCPort((*COSHdl)->offCGrafPtr);
  146.         /* Arrgh !! Batten down the hatches: */
  147.         MoveHHi( ((*COSHdl)->offCGrafPtr)->portPixMap );
  148.         HLock( ((*COSHdl)->offCGrafPtr)->portPixMap );
  149.         maxDepth = (*( ((**COSHdl).offCGrafPtr)->portPixMap ))->pixelSize;
  150.  
  151.     };   /* else: gMac2 */
  152.  
  153.  /* CanNOT use my GlobalLocal PROC because we may have dragged our
  154.     window to a secondary screen.  "Global" here is with respect to
  155.     the main screen and "Local" is with respect to the secondary screen.
  156.  
  157.     From Forrest Tanaka:
  158.     When GetMaxDevice returns the secondary screen's GDevice & we set that
  159.     to the current GDevice, then OpenCPort creates a CGrafPort which has a
  160.     portRect = (**((**GetMainDevice).gdPMap)).bounds which is in the global
  161.     coordinates for all the screens' pixel images with a topLeft = (0,0).
  162.     The new (**CGrafPort.portPixMap).bounds is in the local coordinates of
  163.     the secondary screen with a topLeft = (0,-640), for example.
  164.  
  165.     In effect, the port that OpenCPort gives you is NOT a valid port because
  166.     the portRect pertains to the wrong screen.  This means that calling
  167.     GlobalLocal shifts the localRect waaaaay over somewhere ... BECAUSE
  168.     the difference between the above portRect and PixMap bounds is SO large: */
  169.  
  170.     localRect = globRect;
  171.     OffsetRect(&localRect, screenBits.bounds.left, screenBits.bounds.top);
  172.  
  173.  /* However, before we do ANYthing more, we should set the
  174.     off-screen's visRgn to the FULL size of the input rect so the
  175.     image stays whole even when the window has been dragged partly
  176.     beyond the physical edge(s) of the screen.  Otherwise, the
  177.     (**visRgn).rgnBBox in local coordinates remains equal to
  178.     screenBits.bounds as initialized when _Open(C)Port was called:    */
  179.  
  180.     if (gMac2)
  181.     {
  182.         RectRgn( ((*COSHdl)->offCGrafPort).visRgn, &localRect );
  183.         ((*COSHdl)->offCGrafPort).portRect = localRect;
  184.     }
  185.     else
  186.     {
  187.         RectRgn( ((*COSHdl)->offGrafPort).visRgn, &localRect );
  188.         ((*COSHdl)->offGrafPort).portRect = localRect;
  189.     };
  190.  
  191.  /* We are now ready to calculate the size of the pixel image we will need.
  192.     Then we can set the location-specific and size-specific information of
  193.     the pixel map.  Since Color QuickDraw distinguishes between a bitmap and
  194.     a pixel map by checking the high bit of rowBytes, we need to set it.     */
  195.  
  196.     /* # of words: */
  197.     offRowBytes = (maxDepth * (localRect.right - localRect.left) + 15) / 16;
  198.     if (offRowBytes % 2)    offRowBytes++;        /* ... made even. */
  199.     offRowBytes *= 2;                            /* Back to bytes. */
  200.     sizeOfOff = (long)(localRect.bottom - localRect.top) * offRowBytes;
  201.  
  202.     /* Allocate space for the pixel image: */
  203.     (*COSHdl)->myBits = NewClearHandle(sizeOfOff);
  204.     if (MemError() != noErr)    return ( ErrorOut(NewBaseAddrPtrError, COSHdl) );
  205.  
  206.     MoveHHi((*COSHdl)->myBits);
  207.     HLock((*COSHdl)->myBits);
  208.  
  209.  /* NOTE that we're filling in the BitMap/PixMap fields of the new Port
  210.     directly, so we do NOT call _SetPortBits or _SetCPortPix later:        */
  211.  
  212.     if (gMac2)
  213.     {
  214.         (**( ((**COSHdl).offCGrafPtr)->portPixMap )).baseAddr = 
  215.                     *( (**COSHdl).myBits );
  216.         /* Remember to be a PixMap: */
  217.         (**( ((**COSHdl).offCGrafPtr)->portPixMap )).rowBytes = offRowBytes | 0x8000;
  218.         (**( ((**COSHdl).offCGrafPtr)->portPixMap )).bounds = localRect;
  219.  
  220.         (**COSHdl).offBitMapPtr =
  221.                     (BitMapPtr) (* (((**COSHdl).offCGrafPtr)->portPixMap) );
  222.     }   /* if aMac2 */
  223.  
  224.     else   /* definitely ... "YUCKY" black-and-white. */
  225.     {
  226.         ((**COSHdl).offGrafPtr)->portBits.baseAddr = *( (**COSHdl).myBits );
  227.         ((**COSHdl).offGrafPtr)->portBits.rowBytes = offRowBytes;
  228.         ((**COSHdl).offGrafPtr)->portBits.bounds = localRect;
  229.  
  230.         (**COSHdl).offBitMapPtr = &( ((**COSHdl).offGrafPtr)->portBits );
  231.     };
  232.  
  233.     if (gMac2)
  234.     {
  235.      /* Next, we clone the color table of the maxDevice
  236.         and put it into our off-screen pixel map.        */
  237.  
  238.         (**COSHdl).ourCTHandle = (
  239.                 **(( **((*COSHdl)->myMaxDevice) ).gdPMap) 
  240.                                  ).pmTable;
  241.         err = HandToHand(&(**COSHdl).ourCTHandle);            /* Clone it. */
  242.         if (err != noErr)    return ( ErrorOut(CloneHdlError, COSHdl));
  243.  
  244.         for (i = 0; i <= (**((**COSHdl).ourCTHandle)).ctSize; i++)
  245.             (**((**COSHdl).ourCTHandle)).ctTable[i].value = i;
  246.  
  247.      /* The following is required to convert GDevice cluts to Pixmap cluts:    */
  248.  
  249.         (**((**COSHdl).ourCTHandle)).ctFlags &= 0x7FFF;
  250.         tempSeed = GetCTSeed();        /* Thanks, Scott Knaster !! */
  251.         (**((**COSHdl).ourCTHandle)).ctSeed = tempSeed;
  252.         /* --> the off-screen map: */
  253.         (**( ((**COSHdl).offCGrafPtr)->portPixMap )).pmTable = (**COSHdl).ourCTHandle;
  254.     };   /* if gMac2 */
  255.  
  256.     *myRect = localRect;                /* Return local screen coordinates. */
  257.  
  258.     return ( ErrorOut(noErr, COSHdl) );    /* Whew !! */
  259.  
  260. }    /* CreateOffScreen*/
  261.  
  262.  
  263.  
  264. /*******************
  265.  Back to "Square 1":
  266.  *******************/
  267.  
  268.  
  269. void    ToOnScreen (OffScreenRecHdl COSHdl)    {
  270. /* COSHdl is locked coming in. */
  271.  
  272.  
  273.     if (gMac2)    SetGDevice((**COSHdl).oldDevice);
  274.     SetPort((**COSHdl).origPort);
  275.  
  276. }    /* ToOnScreen*/
  277.  
  278.  
  279.  
  280. /****************************
  281.  Out with the new.
  282.  
  283.  Whoops -- I meant the old !!
  284.  **************************** */
  285.  
  286.  
  287. void    DisposOffScreen (OffScreenRecHdl *COSHdl)    {
  288.  
  289.  
  290.     if (*COSHdl == nil)    return;
  291.  
  292.     if ((***COSHdl).CreateOffScreenError == MaxDevError)    goto bye;
  293.  
  294.     /* NewBaseAddrPtrError or CloneHdlError or noErr ... */
  295.  
  296.     if (gMac2)
  297.     {
  298.         if ((***COSHdl).CreateOffScreenError == noErr)
  299.             DisposHandle((***COSHdl).ourCTHandle);
  300.         HUnlock((***COSHdl).offCGrafPtr->portPixMap);
  301.         CloseCPort((***COSHdl).offCGrafPtr);
  302.     }
  303.     else    ClosePort((***COSHdl).offGrafPtr);
  304.  
  305.     if ((***COSHdl).CreateOffScreenError != NewBaseAddrPtrError)
  306.     {
  307.         HUnlock((***COSHdl).myBits);
  308.         DisposHandle((***COSHdl).myBits);
  309.     };
  310.  
  311. bye:
  312.     HUnlock(*COSHdl);
  313.     DisposHandle(*COSHdl);
  314.     *COSHdl = nil;                            /* Mark as gone ... */
  315.  
  316. }    /* DisposOffScreen */
  317.  
  318.  
  319.  
  320.  
  321. /*    { end file "off_screen.c" }  */
  322.